Skip to content

[23기_김도현] spring tutorial 미션 제출합니다.#7

Open
kimdoes wants to merge 6 commits intoCEOS-Developers:kimdoesfrom
kimdoes:master
Open

[23기_김도현] spring tutorial 미션 제출합니다.#7
kimdoes wants to merge 6 commits intoCEOS-Developers:kimdoesfrom
kimdoes:master

Conversation

@kimdoes
Copy link

@kimdoes kimdoes commented Mar 14, 2026

No description provided.

datasource:
url: jdbc:mysql://localhost:3306/test_db?allowPublicKeyRetrieval=true&useSSL=false&characterEncoding=UTF-8
username: root
password: leseoul2143**

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2. 로컬 DB이긴 하지만 직접 패스워드를 노출하는 것은 위험할 수도 있고, 추후 협업시 충돌이 잦을 수 있으니 환경변수 파일을 도입해보시는건 어떨까요? 아래 적용 방법 블로그 남길게요!

https://famileyj.tistory.com/40

이 과정을 통해서 스프링은 Bean을 등록하고, 필드에 의존성을 주입한다. 이 과정은 모두 비즈니스 로직이 시작되기 전에 일어나게된다.

이 직후에 postProcessAfterInitialization 어노테이션이 호출되어서 @PostConstruct 메서드가 실행되고, 애플리케이션이 종료되면 ApplicationContext도 같이 제거되고 그 때 빈도 같이 제거된다. 만약 @PreDestroy 어노테이션이 적용된 메서드가 있다면 애플리케이션이 끝나기 전에 호출되어 실행된다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트 스캔과 빈 생성, DI 주입까지의 과정을 코드와 함께 자세하게 적으셨네요! 수고하셨습니다 저는 하나하나 코드를 뜯어볼 생각은 못했는데 덕분에 유익한 시간이었습니다 ㅎㅎ

스프링은 웹 서버의 구동을 더 쉽게 도와주는 프레임워크, 톰캣서버는 스프링을 구동할 수 있는 WAS, 아파치 서버는 요청을 받아서 WAS가 구동되도록하는 웹 서버에 해당한다.

# CGV DB 모델링
https://www.erdcloud.com/d/vXew5ExzkDE48pxDi

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DB 모델링까지 하시느라 수고하셨습니다~
주어진 요구사항 외에도 세세한 부분까지 신경쓰신 게 느껴졌습니다
AudienceData를 따로 분리해 성별, 연령별 변동성이 큰 데이터들을 관리하여 movie 테이블의 비대화를 막으신 인상깊어요
또한 TheatherFood를 통해 동일한 메뉴를 갖되, 매장별로 품절여부를 관리할 수 있다는 부분도 설계에 잘 반영되어있네요!
저는 아직 데이터 모델링 과제를 하지 않았는데 해당부분 반영해서 진행해야겠습니다 ㅎㅎ

스프링은 웹 서버의 구동을 더 쉽게 도와주는 프레임워크, 톰캣서버는 스프링을 구동할 수 있는 WAS, 아파치 서버는 요청을 받아서 WAS가 구동되도록하는 웹 서버에 해당한다.

# CGV DB 모델링
https://www.erdcloud.com/d/vXew5ExzkDE48pxDi
Copy link

@shinae1023 shinae1023 Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다만 몇가지 제안을 드려봅니다

  1. 영화 예매/취소와 관련된 테이블을 추가해 유저가 어떤 영화를 언제 예매 or 취소했는지, 총 결제 금액은 얼마인지 등의 정보를 제공하는 것이 어떨지 제안드립니다!
  2. 어떻게 좌석을 연결할 것인지 한 명이 여러개의 좌석을 예매할 수 있는데 이부분을 어떻게 처리할 것인지에 대한 고민도 나누면 좋을거 같습니다
  3. 극장에는 특별관과 일반관이 있다고 합니다!
  4. 영화에는 여러개의 리뷰가 달릴 수 있고, 영화에는 여러 명의 배우가 배우는 여러개의 영화에 출연할 수 있으므로 movie와 comment 테이블, movie와 actor 테이블의 연관관계 설정은 각각 1:n, n:m이 더 알맞다는 생각이 듭니다
  5. TheaterFood - theater 연관관계는 극장음식 쪽에 극장 아이디가 외래키로 설정되어야 할 것 같습니다
  6. 실제 영화를 볼 때 좌석 번호가 있으니 A열 6번 이런식으로 row, col 정보가 있어야 할 것 같습니다

Pointcut: join point에서 Aspect가 실행될 기준을 뜻한다. 스프링에서는 특정한 표현식 제공하여 Pointcut를 지정할 수 있다.
Advice: join point에서 aspect가 취하는 동작이다.

Proxy: 프록시는 대리인, 대리자의 뜻을 가지고있다. 앞서서 특정 로직이 수행되기 직전 또는 직후에 특정한 기능을 추가할 수 있다고했는데, 그래서 객체가 다른 객체를 호출할 때, 객체가 호출하는게 아니라 호출하는 객체와 똑같은 프록시 객체가 다른 객체를 호출하게된다. 그래서 프록시 객체에 추가적인 로직을 추가할 수 있는 것.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AOP에서 프록시 객체가 원본 객체를 대신해서 호출된다는 점을 잘 짚어주셨습니다!
스프링이 이 가짜 프록시 객체를 만들 때 인터페이스가 있는 경우와 없는 경우에 내부적으로 사용하는 기술이 다르다고 알고 있는데 최신 스프링 부트에서는 어떤 방식을 기본으로 채택하고 있는지, 그리고 그 이유는 무엇인지 같이 공부해보면 좋을 것 같아요!

관련 내용이 담긴 블로그 글 공유합니다!
https://giron.tistory.com/129

Comment on lines +607 to +659
여기서 본격적으로 컴포넌트 스캔 과정에서 얻은 BeanDefinition을 토대로 Bean을 생성한다. BeanDefinition을 기반으로 Bean을 생성해 ApplicationContext에 등록하게된다.

```java
//AbstractAutowireCapableBeanFactory 클래스
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args) throws BeanCreationException {
...
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}
...
}


protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args) throws BeanCreationException {
...
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
...
}
...
}

//이 윗과정에서는 생성된 Bean 토대로 BeanWrapper 클래스를 만든 후에 넘긴다


protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
...

if (hasInstantiationAwareBeanPostProcessors()) {
...

for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
...
}
}

...

if (needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
checkDependencies(beanName, mbd, filteredPds, pvs);
}
...
}
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빈을 생성할 때 doCreateBean에서 populateBean으로 넘어가며 리플렉션을 통해 private 필드에도 접근하여 DI를 주입한다는 부분을 코드로 직접 확인하니 원리가 훨씬 더 잘 와닿았어요~ 정성스러운 정리 감사합니다!

Comment on lines +814 to +820
추가로 스프링은 톰캣이라는 서버를 기본제공한다. 따라서 스프링을 동작하면 톰캣서버 위에서 웹서비스가 이루어진다.

클라이언트가 요청을 보내면 톰캣서버로 보내지고, 톰캣서버는 몇 가지 필터들을 통해 요청을 필터링한 후, 스프링에게 요청을 넘긴다. 이 요청을 받는 역할을 DispatcherServlet이 수행하고, DispathcerServlet이 다시 Controller 측으로 데이터를 넘긴다.

이렇게 클라이언트로부터 HTTP 요청을 받아서 간단한 정적 웹페이지를 반환하는 프로그램을 **서버**라고 칭한다. 하지만 데이터베이스 조회, 부가적인 로직 처리 등 정적 웹페이지가 아닌 더 복잡한 동적인 웹페이지를 반환해야할 때가 있는데, 이 때 이 부가적인 로직을 처리하는 미들웨어를 **WAS**(Web Application Server)라고 칭한다. 서버와는 다른 개념이다.

스프링은 웹 서버의 구동을 더 쉽게 도와주는 프레임워크, 톰캣서버는 스프링을 구동할 수 있는 WAS, 아파치 서버는 요청을 받아서 WAS가 구동되도록하는 웹 서버에 해당한다.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

웹 서버와 WAS의 역할을 아파치와 톰캣으로 비유해서 잘 정리해주셨네요!
덕분에 웹서버와 WAS의 차이를 잘 알 수 있었습니다 ㅎㅎ

Comment on lines +375 to +413
```java
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition\> candidates = new LinkedHashSet<\>();

try {
String packageSearchPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern;
...

Resource[] resources = getResourcePatternResolver().getResources(packageSearchPattern);

...

for (Resource resource : resources) {
String filename = resource.getFilename();
...
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);

if (isCandidateComponent(sbd)) {
...
candidates.add(sbd);
}
else {
...
}
}
}
...
}
...
}

return candidates;
}
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스프링이 컴포넌트 스캔을 할 때 단순히 패키지 경로만 훑는 게 아니라, ResourcePatternResolver로 실제 .class 파일들을 다 찾아낸 다음 MetadataReader를 통해 바이트코드 메타데이터를 꼼꼼히 읽어들인다는 과정을 코드로 볼 수 있어서 좋았습니다! 정리하느라 수고 많으셨습니다!

Comment on lines +761 to +786
```java
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
...
try {
...

try {
...

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

...

// Determine handler adapter and invoke the handler.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

...

finally {
...
}
}
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MVC 패턴에서 핸들링 매핑, 핸들러 어댑터 같은 용어들이 텍스트로만 보면 꽤 추상적으로 느껴져서 저도 코드로 3단계로 나눠서 보여줬는데, 이렇게 한 번에 나란히 보여주시니 구조가 더 잘 그려지는 것 같습니다!
정리하시느라 수고 많으셨습니다!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants